package com.example.demo.service;

import com.example.demo.game.GomokuState;


import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.*;

public class GomokuGameService extends JPanel {
    private final int board_Size = 15;      //格子数
    private int cell_Size = 40;      //格子大小
    private int player_Size = 36;
    private int margin = 50;    //边距,用于坐标转换

    private int[][] board;
    private boolean player_black;
    private boolean gameOver = false;
    private boolean Forbidden_hands = true;

    public GomokuGameService() {
        initGame();
        this.addMouseListener(new MouseAdapter() {  //鼠标操作
            @Override
            public void mouseClicked(MouseEvent e) {
                if (gameOver){
                    return;
                }

                int x = e.getX();
                int y = e.getY();
//                x - margin
//                减去边缘留白，得到相对于棋盘内部的坐标
//                + cell_Size / 2
//                加上半个格子的大小，这是为了四舍五入
//                例如：点击位置在格子左半部分算作前一个格子，右半部分算作后一个格子
//                / cell_Size
//                除以每个格子的大小，得到格子索引（从0开始）
                int col = (x - margin + cell_Size / 2) / cell_Size; //列
                int row = (y - margin + cell_Size / 2) / cell_Size; //行

                if (row >= 0 && row < board_Size && col >= 0 && col <board_Size && board[row][col] == 0){
                    board[row][col] = player_black ? 1:2;

                    if (player_black && Forbidden_hands && isForbidden_hands(row, col)) {
                        board[row][col] = 0;
                        JOptionPane.showMessageDialog(null, "黑棋禁手，请重新落子！");
                    } else if (checkWin(row, col)){    //胜利条件判断
                        gameOver = true;
                        String  winner = player_black ? "黑棋" : "白棋";
                        JOptionPane.showMessageDialog(null, winner + "胜利!");
                    } else if (isBoardFull()) {
                        gameOver = true;
                        JOptionPane.showMessageDialog(null,"棋盘已满，平局!");
                    } else {
                        player_black = !player_black;  //切换回合
                    }

                    repaint();  //重绘
                }
            }
        });
    }


    public GomokuState getState() {
        return new GomokuState(board,player_black,gameOver);
    }



    private void initGame() {
        board = new int[board_Size][board_Size];
        player_black = true;
        gameOver = false;
        repaint();  //重绘
    }

    private boolean isBoardFull(){      //方法,判断平局
        for (int row = 0; row < board_Size; row ++){
            for ( int col = 0 ; col < board_Size ; col++){
                if (board[row][col] == 0){
                    return  false;  //有空位
                }
            }
        }
        return true;    //棋盘已满
    }


    public boolean isForbidden_hands(int row, int col){
        if (check_overfive(row,col)){
            return true;
        }

        int three_Count = 0;
        int four_Count = 0;

        int[][] directions = {{0,1}, {1,0}, {1,1}, {1,-1}};

        for (int[] dir : directions){
            LineInfo info = countLine(row, col, dir[0], dir[1]);

            if (info.three) {
                three_Count++;
            } else if (info.four) {
                four_Count++;
            }

            if (three_Count >= 2 || four_Count >=2){
                return true;
            }
        }

        return false;
    }
    //3，4信息
    public class LineInfo{
        boolean three;
        boolean four;
    }


    public LineInfo countLine(int row, int col, int drow, int dcol){

        LineInfo info = new LineInfo();
        int player = board[row][col];

        int[] positive =count_open(row, col, drow, dcol, player);
        int[] unpositive =count_open(row, col, -drow, -dcol, player);

        int counts = 1 + positive[0] + unpositive[0];
        int opens = positive[1] + unpositive[1];

        if (counts == 3 && opens == 2){
            info.three = true;
        } else if (counts == 4 && opens >= 1) {
            info.four = true;
        }

        return info;
    }


    private int[] count_open(int row, int col, int drow, int dcol, int player) {
        int count = 0;
        int open = 0;
        int r = row + drow;  //水平坐标+水平增量
        int c = col + dcol;

        //从 (row, col) 开始，沿着方向 (drow, dcol) 有多少颗与当前玩家 player 同色的连续棋子
        while (r >= 0 && r < board_Size && c >= 0 && c < board_Size && board[r][c] == player){
            count++;
            r += drow;      //如,检查下一个行的位置
            c += dcol;
        }
        if (r >= 0 && r < board_Size && c >= 0 && c < board_Size && board[r][c] == 0){
            open++;
        }
        return new int[]{count, open};
    }


    public boolean check_overfive(int row, int col){
        int[][] directions = {{0,1}, {1,0}, {1,1}, {1,-1}};

        for (int[] dir : directions) {
            int count = countComponents(row, col, dir[0], dir[1], 1);
            if (count > 5) {
                return true;
            }
        }

        return false;
    }


    public boolean checkWin(int row, int col) {          //方法，判断胜利代码
        int plear = board[row][col];
        int[][] directions = {{0,1}, {1,0}, {1,1}, {1,-1}};

        for (int[] dir : directions){
            if (countComponents(row, col, dir[0],dir[1],plear) >= 5){
                return true;
            }
        }
        return false;
    }

    //计算棋子数量，drow，dcol 方向的增量，如(1,0)水平 (0,1)垂直 (1,1)左上到右下——对角线 || player 1黑 2白
    private int countComponents(int row, int col, int drow, int dcol, int player) {     //方法
        int count = 1;      //当前位置已经有一个棋子

        count += countDirection(row, col, drow, dcol, player);  // 正向检查

        count += countDirection(row, col, -drow, -dcol, player);    // 反向检查

        return count;
    }

    //胜利条件判断（水平/垂直/对角线)
    private int countDirection(int row, int col, int drow, int dcol, int player) {      //方法
        int count = 0;
        int r = row + drow;  //水平坐标+水平增量
        int c = col + dcol;

        //从 (row, col) 开始，沿着方向 (drow, dcol) 有多少颗与当前玩家 player 同色的连续棋子
        while (r >= 0 && r < board_Size && c >= 0 && c < board_Size && board[r][c] == player){
            count++;
            r += drow;      //检查下一个行的位置
            c += dcol;
        }
        return count;
    }

    public boolean makeMove(int row, int col) {
        if (gameOver || row < 0 || row >= board_Size || col < 0 || col >= board_Size || board[row][col] != 0) {
            return false;
        }

        board[row][col] = player_black ? 1 : 2;

        if (player_black && Forbidden_hands && isForbidden_hands(row, col)) {
            board[row][col] = 0;
            return false;
        } else if (checkWin(row, col)) {
            gameOver = true;
        } else if (isBoardFull()) {
            gameOver = true;
        } else {
            player_black = !player_black;
        }

        repaint();
        return true;
    }

    public void reset() {
        initGame();
    }
}